package com.genius.workflow.config;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.genius.workflow.realm.PlatformRealm;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: woy
 * @Description: Shiro配置类
 * @Date: Created in 2020/2/3 13:29
 * @param
 */
@Configuration
public class ShiroConfig {

    @Value("${platflorm.server.time.out: #{null}}")
    private long time_out;
    @Value("${platflorm.server.time.out.validation: #{null}}")
    private long time_out_validation;
    @Value("${platflorm.server.switch: #{null}}")
    private boolean session_switch;

    @Value("${outWeb.api.shiro.url: #{null}}")
    private String apiUrls;
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
     *
     * Filter Chain定义说明 1、一个URL可以配置多个Filter，使用逗号分隔 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     *
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        shiroFilterFactoryBean.setUnauthorizedUrl("/tologin");
        // 拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //配置记住我或认证通过可以访问的地址(配置不会被拦截的链接 顺序判断)
        filterChainDefinitionMap.put("/genius/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/tologinShu", "anon");
        filterChainDefinitionMap.put("/loginbycode", "anon");
        filterChainDefinitionMap.put("/adminmanager/login", "anon");
        filterChainDefinitionMap.put("/adminmanager/**", "anon");
        filterChainDefinitionMap.put("/drawImage", "anon");
        filterChainDefinitionMap.put("/dingding/**", "anon");
        filterChainDefinitionMap.put("/mobile_page/**", "anon");
        filterChainDefinitionMap.put("/work_plan_info/**", "anon");
        filterChainDefinitionMap.put("/meeting_info_detail/**", "anon");
        filterChainDefinitionMap.put("/meeting_info/**", "anon");
        filterChainDefinitionMap.put("/process_info_detail/**", "anon");
        filterChainDefinitionMap.put("/shop_open_info/**", "anon");
        filterChainDefinitionMap.put("/notice_info/**", "anon");	
        filterChainDefinitionMap.put("/NoticeImg/**", "anon");
        filterChainDefinitionMap.put("/notice/**", "anon");
        filterChainDefinitionMap.put("/yaohuo/**", "anon");
        filterChainDefinitionMap.put("/typd/**", "anon");
        filterChainDefinitionMap.put("/busswork/**", "anon");
        filterChainDefinitionMap.put("/equipment_info/**", "anon");
        filterChainDefinitionMap.put("/repair_info/**", "anon");
        filterChainDefinitionMap.put("/mobile_pingjia/**", "anon");

        if(StringUtils.isNotBlank(apiUrls)){
            String outUrl [] = apiUrls.split(DefaultConfiguration.separator_douhao);
            for(String url:outUrl){
                System.out.println(url);
                filterChainDefinitionMap.put(apiUrls,"anon");
            }
        }
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        // <!-- 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        if(session_switch){
            ShiroFormAuthenticationFilter shiroFormAuthenticationFilter = new ShiroFormAuthenticationFilter(apiUrls);
            Map<String, Filter> filterMap = new HashMap<>();
            filterMap.put("user",shiroFormAuthenticationFilter);
            shiroFilterFactoryBean.setFilters(filterMap);
            filterChainDefinitionMap.put("/**","user,authc");
        }else{
            filterChainDefinitionMap.put("/reservation/**","anon");
            filterChainDefinitionMap.put("/driverEvaluate/**","anon");
            filterChainDefinitionMap.put("/driverArrivePage/**","anon");
            filterChainDefinitionMap.put("/driverSetOutPage/**","anon");
            filterChainDefinitionMap.put("/driverSubmitPage/**","anon");
            filterChainDefinitionMap.put("/driverPage/**","anon");
            filterChainDefinitionMap.put("/supplierPage/**","anon");
            filterChainDefinitionMap.put("/**", "authc");
        }


        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(getRealm());
        if(session_switch)
            securityManager.setSessionManager(getWebSessionManager());
        //注入记住我管理器;
//        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }
    /**
     * 身份认证realm; (这个需要自己写，账号密码校验；权限等)
     *
     * @return
     */
    @Bean
    public PlatformRealm getRealm() {
        PlatformRealm platformRealm = new PlatformRealm();
        platformRealm.setCachingEnabled(false);
        platformRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return platformRealm;
    }
    /**
     * Shiro生命周期处理器
     * @return
     */
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     * 不要使用 DefaultAdvisorAutoProxyCreator 会出现二次代理的问题，这里不详述
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
//    @Bean
//    @ConditionalOnMissingBean
//    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
//        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
//        defaultAAP.setProxyTargetClass(true);
//        return defaultAAP;
//    }
    /**
     * 加密配置
     * @return
     */
    @Bean(name = "credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        // 散列的次数，比如散列两次，相当于 md5(md5(""));
        hashedCredentialsMatcher.setHashIterations(1024);
        // storedCredentialsHexEncoded默认是true，此时用的是密码加密用的是Hex编码；false时用Base64编码
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }

    //    /**
//     * cookie对象;
//     * 	记住密码实现起来也是比较简单的，主要看下是如何实现的。
//     * @return
//     */
//    @Bean
//    public SimpleCookie rememberMeCookie(){
//        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
//        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
//        simpleCookie.setMaxAge(259200);
//        return simpleCookie;
//    }
//
//    /**
//     * cookie管理对象;
//     * @return
//     */
//    @Bean
//    public CookieRememberMeManager rememberMeManager(){
//        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
//        cookieRememberMeManager.setCookie(rememberMeCookie());
//        return cookieRememberMeManager;
//    }
    @Bean
    public DefaultWebSessionManager getWebSessionManager(){
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setGlobalSessionTimeout(time_out);
        defaultWebSessionManager.setSessionValidationInterval(time_out_validation);
        return defaultWebSessionManager;
    }
}

